From 4871e12b20d9c720ba781ce6564170bcc97fec27 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 11 Jul 2007 13:03:57 +0100 Subject: [PATCH] Add new domctl hypercall to expose current heap values. This functionality is needed for probing how much memory is available in a given node prior to VM creation. Signed-off-by: Ryan Harper Signed-off-by: Keir Fraser --- tools/libxc/xc_domain.c | 21 +++++++++++++++++++++ tools/libxc/xenctrl.h | 14 ++++++++++++++ xen/common/page_alloc.c | 20 +++++++++++++++----- xen/common/sysctl.c | 14 ++++++++++++++ xen/include/public/sysctl.h | 13 +++++++++++++ xen/include/xen/mm.h | 2 ++ 6 files changed, 79 insertions(+), 5 deletions(-) diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c index 11c14247a2..485b260601 100644 --- a/tools/libxc/xc_domain.c +++ b/tools/libxc/xc_domain.c @@ -588,6 +588,27 @@ int xc_domain_ioport_permission(int xc_handle, return do_domctl(xc_handle, &domctl); } +int xc_availheap(int xc_handle, + int min_width, + int max_width, + int node, + uint64_t *bytes) +{ + DECLARE_SYSCTL; + int rc; + + sysctl.cmd = XEN_SYSCTL_availheap; + sysctl.u.availheap.min_bitwidth = min_width; + sysctl.u.availheap.max_bitwidth = max_width; + sysctl.u.availheap.node = node; + + rc = xc_sysctl(xc_handle, &sysctl); + + *bytes = sysctl.u.availheap.avail_bytes; + + return rc; +} + int xc_vcpu_setcontext(int xc_handle, uint32_t domid, uint32_t vcpu, diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h index 6ba6c8b034..93842d4f00 100644 --- a/tools/libxc/xenctrl.h +++ b/tools/libxc/xenctrl.h @@ -616,6 +616,20 @@ int xc_get_pfn_type_batch(int xc_handle, uint32_t dom, /* Get current total pages allocated to a domain. */ long xc_get_tot_pages(int xc_handle, uint32_t domid); +/** + * This function retrieves the the number of bytes available + * in the heap in a specific range of address-widths and nodes. + * + * @parm xc_handle a handle to an open hypervisor interface + * @parm domid the domain to query + * @parm min_width the smallest address width to query (0 if don't care) + * @parm max_width the largest address width to query (0 if don't care) + * @parm node the node to query (-1 for all) + * @parm *bytes caller variable to put total bytes counted + * @return 0 on success, <0 on failure. + */ +int xc_availheap(int xc_handle, int min_width, int max_width, int node, + uint64_t *bytes); /* * Trace Buffer Operations diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c index e2b64dccab..5012c06e42 100644 --- a/xen/common/page_alloc.c +++ b/xen/common/page_alloc.c @@ -936,6 +936,21 @@ void free_domheap_pages(struct page_info *pg, unsigned int order) put_domain(d); } +unsigned long avail_domheap_pages_region( + unsigned int node, unsigned int min_width, unsigned int max_width) +{ + int zone_lo, zone_hi; + + zone_lo = min_width ? (min_width - (PAGE_SHIFT + 1)) : (MEMZONE_XEN + 1); + zone_lo = max_t(int, MEMZONE_XEN + 1, zone_lo); + zone_lo = min_t(int, NR_ZONES - 1, zone_lo); + + zone_hi = max_width ? (max_width - (PAGE_SHIFT + 1)) : (NR_ZONES - 1); + zone_hi = max_t(int, MEMZONE_XEN + 1, zone_hi); + zone_hi = min_t(int, NR_ZONES - 1, zone_hi); + + return avail_heap_pages(zone_lo, zone_hi, node); +} unsigned long avail_domheap_pages(void) { @@ -957,11 +972,6 @@ unsigned long avail_domheap_pages(void) return avail_nrm + avail_dma; } -unsigned long avail_nodeheap_pages(int node) -{ - return avail_heap_pages(0, NR_ZONES - 1, node); -} - static void pagealloc_keyhandler(unsigned char key) { unsigned int zone = MEMZONE_XEN; diff --git a/xen/common/sysctl.c b/xen/common/sysctl.c index efc7c2fd1a..98d3777e0a 100644 --- a/xen/common/sysctl.c +++ b/xen/common/sysctl.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include extern long arch_do_sysctl( struct xen_sysctl *op, XEN_GUEST_HANDLE(xen_sysctl_t) u_sysctl); @@ -169,6 +171,18 @@ long do_sysctl(XEN_GUEST_HANDLE(xen_sysctl_t) u_sysctl) } break; + case XEN_SYSCTL_availheap: + { + op->u.availheap.avail_bytes = avail_domheap_pages_region( + op->u.availheap.node, + op->u.availheap.min_bitwidth, + op->u.availheap.max_bitwidth); + op->u.availheap.avail_bytes <<= PAGE_SHIFT; + + ret = copy_to_guest(u_sysctl, op, 1) ? -EFAULT : 0; + } + break; + default: ret = arch_do_sysctl(op, u_sysctl); break; diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h index 06eb0e78c5..1088a275e0 100644 --- a/xen/include/public/sysctl.h +++ b/xen/include/public/sysctl.h @@ -185,6 +185,18 @@ struct xen_sysctl_getcpuinfo { typedef struct xen_sysctl_getcpuinfo xen_sysctl_getcpuinfo_t; DEFINE_XEN_GUEST_HANDLE(xen_sysctl_getcpuinfo_t); +#define XEN_SYSCTL_availheap 9 +struct xen_sysctl_availheap { + /* IN variables. */ + uint32_t min_bitwidth; /* Smallest address width (zero if don't care). */ + uint32_t max_bitwidth; /* Largest address width (zero if don't care). */ + int32_t node; /* NUMA node of interest (-1 for all nodes). */ + /* OUT variables. */ + uint64_t avail_bytes; /* Bytes available in the specified region. */ +}; +typedef struct xen_sysctl_availheap xen_sysctl_availheap_t; +DEFINE_XEN_GUEST_HANDLE(xen_sysctl_availheap_t); + struct xen_sysctl { uint32_t cmd; uint32_t interface_version; /* XEN_SYSCTL_INTERFACE_VERSION */ @@ -197,6 +209,7 @@ struct xen_sysctl { struct xen_sysctl_getdomaininfolist getdomaininfolist; struct xen_sysctl_debug_keys debug_keys; struct xen_sysctl_getcpuinfo getcpuinfo; + struct xen_sysctl_availheap availheap; uint8_t pad[128]; } u; }; diff --git a/xen/include/xen/mm.h b/xen/include/xen/mm.h index a94d4efdb0..a5183fd125 100644 --- a/xen/include/xen/mm.h +++ b/xen/include/xen/mm.h @@ -61,6 +61,8 @@ struct page_info *__alloc_domheap_pages( struct domain *d, unsigned int cpu, unsigned int order, unsigned int memflags); void free_domheap_pages(struct page_info *pg, unsigned int order); +unsigned long avail_domheap_pages_region( + unsigned int node, unsigned int min_width, unsigned int max_width); unsigned long avail_domheap_pages(void); #define alloc_domheap_page(d) (alloc_domheap_pages(d,0,0)) #define free_domheap_page(p) (free_domheap_pages(p,0)) -- 2.30.2